#include <sys/timerfd.h>
#include <iostream>
#include <unistd.h>
#include <cstring> // memset()

#include "./TimerQueue.h"

namespace Timer
{
    int createTimerFd()
    {
        // 绝对时间，非阻塞，调用exec()关闭
        int timerFd = ::timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
        if (timerFd < 0)
        {
            std::cerr << "Failed to timerfd_create()" << std::endl;
            // TODO: 进一步错误处理
        }
        return timerFd;
    }

    TimerQueue::TimerQueue() : timerFd_(createTimerFd()), timers_()
    {
    }

    TimerQueue::~TimerQueue()
    {
        for (const TimerEntry &timer : this->timers_)
        {
            delete timer.second; // 可以外部const& delete内部
        }
        ::close(this->timerFd_);
    }

    void TimerQueue::addTimer(Timestamp timeout, TimeInterval interval, const TimerCallback &cb)
    {
        Timer *timer = new Timer(timeout, interval, std::move(cb));

        bool eraliestTimerReplaced = this->insertTimer(timer);
        if (eraliestTimerReplaced) // 最早的定时器被替换
        {
            this->resetTimerfd(this->timerFd_, timer->getTimeout()); // 重置timerFd超时时间
        }
    }

    bool TimerQueue::insertTimer(Timer *timer)
    {
        bool eraliestTimerReplaced = false; // 最早的定时器没被替换

        Timestamp timeout = timer->getTimeout();
        if (this->timers_.empty() || timeout < this->timers_.begin()->first) // 将插入的定时器是第一个或超时时间更早
        {
            eraliestTimerReplaced = true; // 最早的定时器被替换
        }

        this->timers_.insert(TimerEntry(timeout, timer));

        return eraliestTimerReplaced;
    }

    void TimerQueue::resetTimerfd(int timerFd, Timestamp timeout)
    {
        struct itimerspec newTimeout;
        memset(&newTimeout, 0, sizeof(newTimeout));

        auto now = std::chrono::system_clock::now();
        // 如果 timeout 在 now 之前，则设置为最小延迟（100 微秒）
        if (timeout <= now)
        {
            newTimeout.it_value.tv_sec = 0;
            newTimeout.it_value.tv_nsec = 100 * 1000; // 100微妙，*1000转换为纳秒
        }
        // 否则新的超时时间是时间差
        else
        {
            auto diff = timeout - now;
            auto diffNs = std::chrono::duration_cast<std::chrono::nanoseconds>(diff).count();

            newTimeout.it_value.tv_sec = static_cast<time_t>(diffNs / 1'000'000'000);
            newTimeout.it_value.tv_nsec = static_cast<long>(diffNs % 1'000'000'000);
        }

        // 标志0：相对时间定时器
        if (::timerfd_settime(this->timerFd_, 0, &newTimeout, nullptr) < 0)
        {
            std::cerr << "Failed to timerfd_settime()" << std::endl;
        }
    }

    void readTimerFd(int timerFd)
    {
        // 象征性地读取数据，实际数据不重要
        uint64_t readBytes{};
        ssize_t readN = ::read(timerFd, &readBytes, sizeof(readBytes));
        if (readN != sizeof(readBytes))
        {
            std::cerr << "Failed to readTimerFd()" << std::endl;
        }
    }

    void TimerQueue::handleTimers()
    {
        auto now = std::chrono::system_clock::now();

        // timerFd读事件
        readTimerFd(this->timerFd_);

        // 处理超时定时器
        std::vector<TimerEntry> timeoutTimers = this->getTimeoutTimers(now);
        for (const TimerEntry &it : timeoutTimers)
        {
            it.second->exec();
        }

        // 重置超时定时器（删除或重复）
        this->resetTimeoutTimers(timeoutTimers, now);
    }

    // TimerQueue::TimerEntry：返回值不在作用域TimerQueue::查找内...，所以要写全
    std::vector<TimerQueue::TimerEntry> TimerQueue::getTimeoutTimers(Timestamp now)
    {
        std::vector<TimerEntry> timeoutTimers{};

        TimerEntry sentinelEntry(now, nullptr);                            // 哨兵now用于查找，第二个参数无所谓
        TimerSet::iterator end = this->timers_.lower_bound(sentinelEntry); // 第一个>=now的，now会比触发时间稍晚不算在超时的
        timeoutTimers.assign(this->timers_.begin(), end);                  // 记录，直接赋值指针比insert()少容量检查
        this->timers_.erase(this->timers_.begin(), end);                   // 删除

        return timeoutTimers;
    }

    void TimerQueue::resetTimeoutTimers(const std::vector<TimerEntry> &timeoutTimers, Timestamp now)
    {
        for (const TimerEntry &it : timeoutTimers)
        {
            if (it.second->getInterval().count() <= 0) // 非重复定时器删除
            {
                delete it.second;
            }
            else // 重复定时器重启
            {
                Timer *timer = it.second;
                timer->restart(now);
                this->insertTimer(timer);
            }

            // if (eraliestTimerReplaced) // 可能重置timerFd ×
            // 可能情况：
            // 第一个是非重复定时器，每2s触发，第4s触发重置timerFd超时时间第6s
            // 第二个是重复定时器，本该在第5s触发，但被6s替换而错过
            if (!this->timers_.empty()) // 必须重置
            {
                this->resetTimerfd(this->timerFd_, this->timers_.begin()->second->getTimeout());
            }
        }
    }
} // namesapce Timer